/*****************************************************************************/
/*                                                                           */
/*    Domino Operation System Driver Module                                  */
/*                                                                           */
/*    Copyright (C) 2013 Laszlo Arvai                                        */
/*                                                                           */
/*    ------------------------------------------------------------------     */
/*    Analog Devices AD779x ADC driver                                       */
/*****************************************************************************/

///////////////////////////////////////////////////////////////////////////////
// Include files
#include <krnlTypes.h>
#include <drvSPI.h>
#include <drvAD779x.h>
#include <drvIOConfig.h>

///////////////////////////////////////////////////////////////////////////////
// Constants
#define AD779x_TIMEOUT 2

///////////////////////////////////////////////////////////////////////////////
// Local functions
static dosByte drvAD779xReadByteRegister(dosByte in_register_index);
static dosWord drvAD779xReadWordRegister(dosByte in_register_index);
static dosDWord drvAD779xReadDataRegister(dosByte in_register_index);

static void drvAD779xWriteByteRegister(dosByte in_register_index, dosByte in_register_value);
static void drvAD779xWriteWordRegister(dosByte in_register_index, dosWord in_register_value);

static dosBool WaitForDataReady(dosWord in_timeout);

dosByte ReadStatus(void)
{
	return drvAD779xReadByteRegister(AD779x_REG_STAT);
}

dosByte ReadVbat(void)
{
	dosDWord battery;

	// set mode
	drvAD779xWriteWordRegister(AD779x_REG_MODE, AD779x_MODE_CONTINOUS | AD779x_MODE_RATE_470Hz);

	// set config
	drvAD779xWriteWordRegister(AD779x_REG_CONF, AD779x_CONF_SET_UNIPOLAR | AD779x_CONF_REF_INTERNAL | AD779x_CONF_BUFFER_ENABLE | AD779x_CONF_CH_AIN6P_AIN6M );

	WaitForDataReady(10);

	battery = drvAD779xReadDataRegister(AD779x_REG_DATA);
}

///////////////////////////////////////////////////////////////////////////////
//! Initializes AD7794 AD converter
void drvAD779xInit(void)
{
	dosByte status;

	InitAD7794CS();
	InitAD7794SPI();

	drvAD779xReset();

	//ReadVbat();

}

///////////////////////////////////////////////////////////////////////////////
//! Resets ADC registers and communication registers
void drvAD779xReset(void)
{
	// CS low
	AD7794CS(PIN_LOW);

	// send 32 bit 1's
	AD7794SendReceiveByte(0xff);
	AD7794SendReceiveByte(0xff);
	AD7794SendReceiveByte(0xff);
	AD7794SendReceiveByte(0xff);

	// CS high
	AD7794CS(PIN_HIGH);

	// 500us delay
	krnlDelay(2);
}

///////////////////////////////////////////////////////////////////////////////
//! Sets mode register contents
//! \param[in] in_mode Mode register value
void drvAD779xSetModeRegister(dosWord in_mode)
{
	drvAD779xWriteWordRegister(AD779x_REG_MODE, in_mode);
}

///////////////////////////////////////////////////////////////////////////////
//! Sets config register contents
//! \param[in] in_mode Mode register value
void drvAD779xSetConfigRegister(dosWord in_config)
{
	drvAD779xWriteWordRegister(AD779x_REG_CONF, in_config);
}

///////////////////////////////////////////////////////////////////////////////
//! Starts async data reading (the SPI bus will be busy)
void drvAD779xAsyncStartDataRead(void)
{
	AD7794CS(PIN_LOW);
}

///////////////////////////////////////////////////////////////////////////////
//! Checks data availability
//! \return True when data is available
dosBool drvAD779xAsyncIsDataAvailable(void)
{
	return AD7794IsRDY();
}

///////////////////////////////////////////////////////////////////////////////
//! Stops data reading without actually reading the data (releases SPI bus)
void drvAD779xAsyncStopDataRead(void)
{
	AD7794CS(PIN_HIGH);
}

///////////////////////////////////////////////////////////////////////////////
//! Reads the data and releases the SPI bus
//! \return Data
dosDWord drvAD779xAsyncReadDataAndStop(void)
{
	return drvAD779xReadDataRegister(AD779x_REG_DATA);
}

/*****************************************************************************/
/* Local functions                                                           */
/*****************************************************************************/

///////////////////////////////////////////////////////////////////////////////
//! Waits for data ready signal with a timeout
//! \param[in] in_timeout Timeout value in ms
//! \return True if data ready condition is deceted, false if timeout occured
static dosBool WaitForDataReady(dosWord in_timeout)
{
	// CS low
	AD7794CS(PIN_LOW);

	dosWord start_time = krnlGetSystemTimer();
	do
	{
		if(AD7794IsRDY())
			return dosTrue;
	} while(krnlGetTimeSince(start_time) < in_timeout);

	// CS high
	AD7794CS(PIN_HIGH);

	return dosFalse;
}

///////////////////////////////////////////////////////////////////////////////
//! Writes byte (8bit) wide registers
//! \param[in] in_register_index Register index to read. Use AD779x_REG_xxx constants.
//! \param[in] in_register_value Register value to write.
//! \return Register value
static void drvAD779xWriteByteRegister(dosByte in_register_index, dosByte in_register_value)
{
	AD7794CS(PIN_LOW);

	AD7794SendReceiveByte(AD779x_COMM_WEN | AD779x_COMM_WRITE | AD779x_COMM_ADDR(in_register_index));
	AD7794SendReceiveByte(in_register_value);

	AD7794CS(PIN_HIGH);
}

///////////////////////////////////////////////////////////////////////////////
//! Writes word (16bit) wide registers
//! \param[in] in_register_index Register index to read. Use AD779x_REG_xxx constants.
//! \param[in] in_register_value Register value to write.
//! \return Register value
static void drvAD779xWriteWordRegister(dosByte in_register_index, dosWord in_register_value)
{
	AD7794CS(PIN_LOW);

	AD7794SendReceiveByte(AD779x_COMM_WEN | AD779x_COMM_WRITE | AD779x_COMM_ADDR(in_register_index));
	AD7794SendReceiveByte(in_register_value >> 8);
	AD7794SendReceiveByte(in_register_value & 0xff);

	AD7794CS(PIN_HIGH);
}

///////////////////////////////////////////////////////////////////////////////
//! Reads byte (8bit) wide registers
//! \param[in] in_register_index Register index to read. Use AD779x_REG_xxx constants.
//! \return Register value
static dosByte drvAD779xReadByteRegister(dosByte in_register_index)
{
	dosByte result;

	AD7794CS(PIN_LOW);

	AD7794SendReceiveByte(AD779x_COMM_WEN | AD779x_COMM_READ | AD779x_COMM_ADDR(in_register_index));
	result = AD7794SendReceiveByte(0);

	AD7794CS(PIN_HIGH);

	return result;
}

///////////////////////////////////////////////////////////////////////////////
//! Reads word (16bit) wide registers
//! \param[in] in_register_index Register index to read. Use AD779x_REG_xxx constants.
//! \return Register value
static dosWord drvAD779xReadWordRegister(dosByte in_register_index)
{
	dosWord result;

	AD7794CS(PIN_LOW);

	AD7794SendReceiveByte(AD779x_COMM_WEN | AD779x_COMM_READ | AD779x_COMM_ADDR(in_register_index));
	result = AD7794SendReceiveByte(0) << 8;
	result += AD7794SendReceiveByte(0);

	AD7794CS(PIN_HIGH);

	return result;
}

///////////////////////////////////////////////////////////////////////////////
//! Reads data (24bit) wide registers
//! \param[in] in_register_index Register index to read. Use AD779x_REG_xxx constants.
//! \return Register value
static dosDWord drvAD779xReadDataRegister(dosByte in_register_index)
{
	dosDWord result;

	AD7794CS(PIN_LOW);

	AD7794SendReceiveByte(AD779x_COMM_WEN | AD779x_COMM_READ | AD779x_COMM_ADDR(in_register_index));
	result = ((dosDWord)AD7794SendReceiveByte(0)) << 16;
	result += AD7794SendReceiveByte(0) << 8;
	result += AD7794SendReceiveByte(0);

	AD7794CS(PIN_HIGH);

	return result;
}
